﻿namespace UnitFundProfitability.DataMigrationTest
{
	using System;
	using System.Configuration;
	using System.Data.EntityClient;
	using System.Data.SqlClient;
	using System.Data.SqlServerCe;
	using System.IO;
	using System.Reflection;
	using Microsoft.VisualStudio.TestTools.UnitTesting;
	using UnitFundProfitability.DataMigration;

	/// <summary>
	/// This is a test class for DataMigrationHelperTest and is intended
	/// to contain all DataMigrationHelperTest Unit Tests.
	/// </summary>
	[TestClass()]
	public class DataMigrationHelperTest
	{
		private TestContext testContextInstance;

		/// <summary>
		/// Gets or sets the test context which provides
		/// information about and functionality for the current test run.
		/// </summary>
		/// <value>The test context.</value>
		public TestContext TestContext
		{
			get
			{
				return testContextInstance;
			}

			set
			{
				testContextInstance = value;
			}
		}

		/// <summary>
		/// A test for Migrate.
		/// </summary>
		[TestMethod()]
		public void MigrateTest()
		{
			DeleteDatabase();
			AssertException(() => DataMigrationHelper.Migrate(null), typeof(ArgumentException));
			AssertException(() => DataMigrationHelper.Migrate(string.Empty), typeof(ArgumentException));
			AssertException(() => DataMigrationHelper.Migrate(" "), typeof(ArgumentException));
			using (SqlCeConnection connection = CreateConnection())
			{
				DataMigrationHelper.Migrate(connection.DataSource);
				using (SqlCeCommand command = connection.CreateCommand())
				{
					command.CommandText = "select PropertyValue from DbConfig where PropertyName = 'DatabaseVersion'";
					connection.Open();
					string databaseVersion = (string)command.ExecuteScalar();
					string expected = "1.3.0.0";
					Assert.AreEqual(expected, databaseVersion);
				}
				using (SqlCeCommand command = connection.CreateCommand())
				{
					command.CommandText = "select count(*) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'UnitFund' and COLUMN_NAME = 'MarkdownPeriod'";
					int neededColumnExists = (int)command.ExecuteScalar();
					Assert.IsTrue(neededColumnExists == 1);
				}
			}
		}

		/// <summary>
		/// A test for DefineDatabaseVersion.
		/// </summary>
		[TestMethod()]
		[DeploymentItem("UnitFundProfitability.DataMigration.dll")]
		public void DefineDatabaseVersionTest()
		{
			DeleteDatabase();
			string expected = "0.0.0.0";
			string actual;
			using (SqlCeConnection connection = CreateConnection())
			{
				actual = DataMigrationHelper_Accessor.DefineDatabaseVersion(connection.DataSource);
				Assert.AreEqual(expected, actual);
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				using (Stream resourceStream = executingAssembly.GetManifestResourceStream(GetType(), "database.sdf"))
				{
					using (FileStream databaseFile = new FileStream(connection.DataSource, FileMode.Create, FileAccess.Write))
					{
						resourceStream.CopyTo(databaseFile);
					}
				}
				expected = "1.0.0.0";
				actual = DataMigrationHelper_Accessor.DefineDatabaseVersion(connection.DataSource);
				Assert.AreEqual(expected, actual);
				using (SqlCeCommand command = connection.CreateCommand())
				{
					command.CommandText = "create table [Operation] (IsPendingOperation [bit] not null)";
					connection.Open();
					command.ExecuteNonQuery();
				}
				expected = "1.1.0.0";
				actual = DataMigrationHelper_Accessor.DefineDatabaseVersion(connection.DataSource);
				Assert.AreEqual(expected, actual);
			}
		}

		/// <summary>
		/// A test for GetDatabasePatch.
		/// </summary>
		[TestMethod()]
		[DeploymentItem("UnitFundProfitability.DataMigration.dll")]
		public void GetDatabasePatchTest()
		{
			DeleteDatabase();
			string actual = DataMigrationHelper_Accessor.GetDatabasePatch("0.0.0.0");
			Assert.IsFalse(string.IsNullOrWhiteSpace(actual));
		}

		/// <summary>
		/// A test for ApplyPatch.
		/// </summary>
		[TestMethod()]
		[DeploymentItem("UnitFundProfitability.DataMigration.dll")]
		public void ApplyPatchTest()
		{
			DeleteDatabase();
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			using (SqlCeConnection connection = CreateConnection())
			{
				using (Stream resourceStream = executingAssembly.GetManifestResourceStream(GetType(), "database.sdf"))
				{
					using (FileStream databaseFile = new FileStream(connection.DataSource, FileMode.Create, FileAccess.Write))
					{
						resourceStream.CopyTo(databaseFile);
					}
				}
				DataMigrationHelper_Accessor.ApplyPatch("create table [Operation] (Id [bit] not null);\r\ngo\r\nalter table Operation add IsPendingOperation [bit] null;\r\ngo\r\nalter table Operation alter column IsPendingOperation [bit] not null;");
				string expected = "1.1.0.0";
				string actual = DataMigrationHelper_Accessor.DefineDatabaseVersion(connection.DataSource);
				Assert.AreEqual(expected, actual);
			}
		}

		/// <summary>
		/// A test for CreateConnection.
		/// </summary>
		[TestMethod()]
		[DeploymentItem("UnitFundProfitability.DataMigration.dll")]
		public void CreateConnectionTest()
		{
			DeleteDatabase();
			using (SqlCeConnection expected = CreateConnection())
			{
				using (SqlCeConnection actual = DataMigrationHelper_Accessor.CreateConnection())
				{
					Assert.AreEqual(expected.ConnectionString, actual.ConnectionString);
				}
			}
		}

		/// <summary>
		/// A test for GetResourceAsString.
		/// </summary>
		[TestMethod()]
		[DeploymentItem("UnitFundProfitability.DataMigration.dll")]
		public void GetResourceAsStringTest()
		{
			DeleteDatabase();
			string resourceName = "CheckIfDbConfigExists.sqlce";
			string actual = DataMigrationHelper_Accessor.GetResourceAsString(resourceName);
			Assert.IsFalse(string.IsNullOrWhiteSpace(actual));
		}

		/// <summary>
		/// A test for DefineDatabaseVersionUsingIsPendingOperationColumn.
		/// </summary>
		[TestMethod()]
		[DeploymentItem("UnitFundProfitability.DataMigration.dll")]
		public void DefineDatabaseVersionUsingIsPendingOperationColumnTest()
		{
			DeleteDatabase();
			using (SqlCeConnection connection = CreateConnection())
			{
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				using (Stream resourceStream = executingAssembly.GetManifestResourceStream(GetType(), "database.sdf"))
				{
					using (FileStream databaseFile = new FileStream(connection.DataSource, FileMode.Create, FileAccess.Write))
					{
						resourceStream.CopyTo(databaseFile);
					}
				}
				string expected = "1.0.0.0";
				string actual = DataMigrationHelper_Accessor.DefineDatabaseVersion(connection.DataSource);
				Assert.AreEqual(expected, actual);
				using (SqlCeCommand command = connection.CreateCommand())
				{
					command.CommandText = "create table [Operation] (IsPendingOperation [bit] not null)";
					connection.Open();
					command.ExecuteNonQuery();
				}
				expected = "1.1.0.0";
				actual = DataMigrationHelper_Accessor.DefineDatabaseVersion(connection.DataSource);
				Assert.AreEqual(expected, actual);
			}
		}

		/// <summary>
		/// Creates the connection.
		/// </summary>
		/// <returns>Sql connection.</returns>
		private static SqlCeConnection CreateConnection()
		{
			EntityConnection entityConnection = new EntityConnection(ConfigurationManager.ConnectionStrings["UnitFundsEntities"].ConnectionString);
			SqlConnectionStringBuilder connectionStringBuilder = new SqlConnectionStringBuilder();
			connectionStringBuilder.DataSource = entityConnection.DataSource;
			return new SqlCeConnection(connectionStringBuilder.ConnectionString);
		}

		/// <summary>
		/// Asserts the exception.
		/// </summary>
		/// <param name="action">The action.</param>
		/// <param name="expectedExceptionType">Expected type of the exception.</param>
		private static void AssertException(Action action, Type expectedExceptionType)
		{
			bool exceptionThrown = false;
			try
			{
				action();
			}
			catch (Exception ex)
			{
				exceptionThrown = true;
				Assert.IsInstanceOfType(ex, expectedExceptionType);
			}
			Assert.IsTrue(exceptionThrown);
		}

		/// <summary>
		/// Deletes the database.
		/// </summary>
		private static void DeleteDatabase()
		{
			using (SqlCeConnection connection = CreateConnection())
			{
				if (File.Exists(connection.DataSource))
				{
					File.Delete(connection.DataSource);
				}
			}
		}
	}
}
